home *** CD-ROM | disk | FTP | other *** search
/ Total Network Tools 2002 / NextStepPublishing-TotalNetworkTools2002-Win95.iso / Archive / Misc Servers / Zope.exe / WIN32PDHQUERY.PYC (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  1999-07-21  |  23.5 KB  |  593 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 1.5)
  3.  
  4. '''
  5. Performance Data Helper (PDH) Query Classes
  6.  
  7. Wrapper classes for end-users and high-level access to the PDH query
  8. mechanisms.  PDH is a win32-specific mechanism for accessing the
  9. performance data made available by the system.  The Python for Windows
  10. PDH module does not implement the "Registry" interface, implementing
  11. the more straightforward Query-based mechanism.
  12.  
  13. The basic idea of a PDH Query is an object which can query the system
  14. about the status of any number of "counters."  The counters are paths
  15. to a particular piece of performance data.  For instance, the path 
  16. \'\\Memory\\Available Bytes\' describes just about exactly what it says
  17. it does, the amount of free memory on the default computer expressed 
  18. in Bytes.  These paths can be considerably more complex than this, 
  19. but part of the point of this wrapper module is to hide that
  20. complexity from the end-user/programmer.
  21.  
  22. EXAMPLE: A more complex Path
  23. \t\'\\\\RAISTLIN\\PhysicalDisk(_Total)\\Avg. Disk Bytes/Read\'
  24. \tRaistlin --> Computer Name
  25. \tPhysicalDisk --> Object Name
  26. \t_Total --> The particular Instance (in this case, all instances, i.e. all drives)
  27. \tAvg. Disk Bytes/Read --> The piece of data being monitored.
  28.  
  29. EXAMPLE: Collecting Data with a Query
  30. \tAs an example, the following code implements a logger which allows the
  31. \tuser to choose what counters they would like to log, and logs those
  32. \tcounters for 30 seconds, at two-second intervals.
  33. \t
  34. \tquery = Query()
  35. \tquery.addcounterbybrowsing()
  36. \tquery.collectdatafor(30,2)
  37. \t
  38. \tThe data is now stored in a list of lists as:
  39. \tquery.curresults
  40. \t
  41. \tThe counters(paths) which were used to collect the data are:
  42. \tquery.curpaths
  43. \t
  44. \tYou can use the win32pdh.ParseCounterPath(path) utility function
  45. \tto turn the paths into more easily read values for your task, or
  46. \twrite the data to a file, or do whatever you want with it.
  47.  
  48. OTHER NOTABLE METHODS:
  49. \tquery.collectdatawhile(period) # start a logging thread for collecting data
  50. \tquery.collectdatawhile_stop() # signal the logging thread to stop logging
  51. \tquery.collectdata() # run the query only once
  52. \tquery.addperfcounter(object, counter, machine=None) # add a standard performance counter
  53. \tquery.addinstcounter(object, counter,machine=None,objtype = \'Process\',volatile=1,format = win32pdh.PDH_FMT_LONG) # add a possibly volatile counter
  54.  
  55. ### Known bugs and limitations ###
  56. Due to a problem with threading under the PythonWin interpreter, there
  57. will be no data logged if the PythonWin window is not the foreground
  58. application.  Workaround: scripts using threading should be run in the
  59. python.exe interpreter.
  60.  
  61. The volatile-counter handlers are possibly buggy, they haven\'t been
  62. tested to any extent.  The wrapper Query makes it safe to pass invalid
  63. paths (a -1 will be returned, or the Query will be totally ignored,
  64. depending on the missing element), so you should be able to work around
  65. the error by including all possible paths and filtering out the -1\'s.
  66.  
  67. There is no way I know of to stop a thread which is currently sleeping,
  68. so you have to wait until the thread in collectdatawhile is activated
  69. again.  This might become a problem in situations where the collection
  70. period is multiple minutes (or hours, or whatever).
  71.  
  72. Should make the win32pdh.ParseCounter function available to the Query
  73. classes as a method or something similar, so that it can be accessed
  74. by programmes that have just picked up an instance from somewhere.
  75.  
  76. Should explicitly mention where QueryErrors can be raised, and create a
  77. full test set to see if there are any uncaught win32api.error\'s still
  78. hanging around.
  79.  
  80. When using the python.exe interpreter, the addcounterbybrowsing-
  81. generated browser window is often hidden behind other windows.  No known
  82. workaround other than Alt-tabing to reach the browser window.
  83.  
  84. ### Other References ###
  85. The win32pdhutil module (which should be in the %pythonroot%/win32/lib 
  86. directory) provides quick-and-dirty utilities for one-off access to
  87. variables from the PDH.  Almost everything in that module can be done
  88. with a Query object, but it provides task-oriented functions for a
  89. number of common one-off tasks.
  90.  
  91. If you can access the MS Developers Network Library, you can find
  92. information about the PDH API as MS describes it.  In general the
  93. Python version of the API is just a wrapper around the Query-based
  94. version of this API (as far as I can see), so you can learn what
  95. you need to from there.  From what I understand, the MSDN Online 
  96. resources are available for the price of signing up for them.  I can\'t
  97. guarantee how long that\'s supposed to last. (Or anything for that
  98. matter).
  99. http://premium.microsoft.com/isapi/devonly/prodinfo/msdnprod/msdnlib.idc?theURL=/msdn/library/sdkdoc/perfdata_4982.htm
  100.  
  101. The eventual plan is for my (Mike Fletcher\'s) Starship account to include
  102. a section on NT Administration, and the Query is the first project
  103. in this plan.  There should be an article describing the creation of
  104. a simple logger there, but the example above is 90% of the work of
  105. that project, so don\'t sweat it if you don\'t find anything there.
  106. (currently the account hasn\'t been set up).
  107. http://starship.skyport.net/crew/mcfletch/
  108.  
  109. If you need to contact me immediately, (why I can\'t imagine), you can
  110. email me at mcfletch@golden.net, or just post your question to the
  111. Python newsgroup with a catchy subject line.
  112. news:comp.lang.python
  113.  
  114. ### Other Stuff ###
  115. The Query classes are by Mike Fletcher, with the working code
  116. being corruptions of Mark Hammonds win32pdhutil module.
  117.  
  118. Use at your own risk, no warranties, no guarantees, no assurances,
  119. if you use it, you accept the risk of using it, etceteras.
  120.  
  121. '''
  122. import win32pdh
  123. import string
  124. import win32api
  125. import time
  126. import thread
  127. import copy
  128.  
  129. class BaseQuery:
  130.     """
  131. \tProvides wrapped access to the Performance Data Helper query
  132. \tobjects, generally you should use the child class Query
  133. \tunless you have need of doing weird things :)
  134.  
  135. \tThis class supports two major working paradigms.  In the first,
  136. \tyou open the query, and run it as many times as you need, closing
  137. \tthe query when you're done with it.  This is suitable for static
  138. \tqueries (ones where processes being monitored don't disappear).
  139.  
  140. \tIn the second, you allow the query to be opened each time and
  141. \tclosed afterward.  This causes the base query object to be
  142. \tdestroyed after each call.  Suitable for dynamic queries (ones
  143. \twhich watch processes which might be closed while watching.)
  144. \t"""
  145.     
  146.     def __init__(self, paths = None):
  147.         """
  148. \t\tThe PDH Query object is initialised with a single, optional
  149. \t\tlist argument, that must be properly formatted PDH Counter
  150. \t\tpaths.  Generally this list will only be provided by the class
  151. \t\twhen it is being unpickled (removed from storage).  Normal
  152. \t\tuse is to call the class with no arguments and use the various
  153. \t\taddcounter functions (particularly, for end user's, the use of
  154. \t\taddcounterbybrowsing is the most common approach)  You might
  155. \t\twant to provide the list directly if you want to hard-code the
  156. \t\telements with which your query deals (and thereby avoid the
  157. \t\toverhead of unpickling the class).
  158. \t\t"""
  159.         self.counters = []
  160.         if paths:
  161.             self.paths = paths
  162.         else:
  163.             self.paths = []
  164.         self._base = None
  165.         self.active = 0
  166.         self.curpaths = []
  167.  
  168.     
  169.     def addcounterbybrowsing(self, flags = win32pdh.PERF_DETAIL_WIZARD, windowtitle = 'Python Browser'):
  170.         '''
  171. \t\tAdds possibly multiple paths to the paths attribute of the query,
  172. \t\tdoes this by calling the standard counter browsing dialogue.  Within
  173. \t\tthis dialogue, find the counter you want to log, and click: Add,
  174. \t\trepeat for every path you want to log, then click on close.  The
  175. \t\tpaths are appended to the non-volatile paths list for this class,
  176. \t\tsubclasses may create a function which parses the paths and decides
  177. \t\t(via heuristics) whether to add the path to the volatile or non-volatile
  178. \t\tpath list.
  179. \t\te.g.:
  180. \t\t\tquery.addcounter()
  181. \t\t'''
  182.         win32pdh.BrowseCounters(None, 0, self.paths.append, flags, windowtitle)
  183.  
  184.     
  185.     def rawaddcounter(self, object, counter, instance = None, inum = -1, machine = None):
  186.         '''
  187. \t\tAdds a single counter path, without catching any exceptions.
  188. \t\t
  189. \t\tSee addcounter for details.
  190. \t\t'''
  191.         path = win32pdh.MakeCounterPath((machine, object, instance, None, inum, counter))
  192.         self.paths.append(path)
  193.  
  194.     
  195.     def addcounter(self, object, counter, instance = None, inum = -1, machine = None):
  196.         """
  197. \t\tAdds a single counter path to the paths attribute.  Normally
  198. \t\tthis will be called by a child class' speciality functions,
  199. \t\trather than being called directly by the user. (Though it isn't
  200. \t\thard to call manually, since almost everything is given a default)
  201. \t\tThis method is only functional when the query is closed (or hasn't
  202. \t\tyet been opened).  This is to prevent conflict in multi-threaded
  203. \t\tquery applications).
  204. \t\te.g.:
  205. \t\t\tquery.addcounter('Memory','Available Bytes')
  206. \t\t"""
  207.         if not (self.active):
  208.             
  209.             try:
  210.                 self.rawaddcounter(object, counter, instance, inum, machine)
  211.                 return 0
  212.             except win32api.error:
  213.                 return -1
  214.  
  215.         else:
  216.             return -1
  217.  
  218.     
  219.     def open(self):
  220.         """
  221. \t\tBuild the base query object for this wrapper,
  222. \t\tthen add all of the counters required for the query.
  223. \t\tRaise a QueryError if we can't complete the functions.
  224. \t\tIf we are already open, then do nothing.
  225. \t\t"""
  226.         if not (self.active):
  227.             self.curpaths = copy.copy(self.paths)
  228.             
  229.             try:
  230.                 base = win32pdh.OpenQuery()
  231.                 for path in self.paths:
  232.                     
  233.                     try:
  234.                         self.counters.append(win32pdh.AddCounter(base, path))
  235.                     except win32api.error:
  236.                         0
  237.                         0
  238.                         self.paths
  239.                         self.counters.append(0)
  240.                     except:
  241.                         0
  242.  
  243.                 
  244.                 self._base = base
  245.                 self.active = 1
  246.                 return 0
  247.             except:
  248.                 
  249.                 try:
  250.                     self.killbase(base)
  251.                 except NameError:
  252.                     pass
  253.  
  254.                 self.active = 0
  255.                 self.curpaths = []
  256.                 raise QueryError(self)
  257.  
  258.         
  259.         return 1
  260.  
  261.     
  262.     def killbase(self, base = None):
  263.         """
  264. \t\t### This is not a public method
  265. \t\tMission critical function to kill the win32pdh objects held
  266. \t\tby this object.  User's should generally use the close method
  267. \t\tinstead of this method, in case a sub-class has overridden
  268. \t\tclose to provide some special functionality.
  269. \t\t"""
  270.         self._base = None
  271.         counters = self.counters
  272.         self.counters = []
  273.         self.active = 0
  274.         
  275.         try:
  276.             map(win32pdh.RemoveCounter, counters)
  277.         except:
  278.             pass
  279.  
  280.         
  281.         try:
  282.             win32pdh.CloseQuery(base)
  283.         except:
  284.             pass
  285.  
  286.         del counters
  287.         del base
  288.  
  289.     
  290.     def close(self):
  291.         '''
  292. \t\tMakes certain that the underlying query object has been closed,
  293. \t\tand that all counters have been removed from it.  This is
  294. \t\timportant for reference counting.
  295. \t\tYou should only need to call close if you have previously called
  296. \t\topen.  The collectdata methods all can handle opening and
  297. \t\tclosing the query.  Calling close multiple times is acceptable.
  298. \t\t'''
  299.         
  300.         try:
  301.             self.killbase(self._base)
  302.         except AttributeError:
  303.             self.killbase()
  304.  
  305.  
  306.     __del__ = close
  307.     
  308.     def collectdata(self, format = win32pdh.PDH_FMT_LONG):
  309.         '''
  310. \t\tReturns the formatted current values for the Query
  311. \t\t'''
  312.         if self._base:
  313.             return self.collectdataslave(format)
  314.         else:
  315.             self.open()
  316.             temp = self.collectdataslave(format)
  317.             self.close()
  318.             return temp
  319.  
  320.     
  321.     def collectdataslave(self, format = win32pdh.PDH_FMT_LONG):
  322.         '''
  323. \t\t### Not a public method
  324. \t\tCalled only when the Query is known to be open, runs over
  325. \t\tthe whole set of counters, appending results to the temp,
  326. \t\treturns the values as a list.
  327. \t\t'''
  328.         
  329.         try:
  330.             win32pdh.CollectQueryData(self._base)
  331.             temp = []
  332.             for counter in self.counters:
  333.                 ok = 0
  334.                 
  335.                 try:
  336.                     if counter:
  337.                         temp.append(win32pdh.GetFormattedCounterValue(counter, format)[1])
  338.                         ok = 1
  339.                 except win32api.error:
  340.                     0
  341.                     0
  342.                     self.counters
  343.                 except:
  344.                     0
  345.  
  346.             
  347.             return temp
  348.         except win32api.error:
  349.             return [
  350.                 -1] * len(self.counters)
  351.  
  352.  
  353.     
  354.     def __getinitargs__(self):
  355.         '''
  356. \t\t### Not a public method
  357. \t\t'''
  358.         return (self.paths,)
  359.  
  360.  
  361.  
  362. class Query(BaseQuery):
  363.     '''
  364. \tPerformance Data Helper(PDH) Query object:
  365. \t
  366. \tProvides a wrapper around the native PDH query object which
  367. \tallows for query reuse, query storage, and general maintenance
  368. \tfunctions (adding counter paths in various ways being the most
  369. \tobvious ones).
  370. \t'''
  371.     
  372.     def __init__(self, *args, **namedargs):
  373.         """
  374. \t\tThe PDH Query object is initialised with a single, optional
  375. \t\tlist argument, that must be properly formatted PDH Counter
  376. \t\tpaths.  Generally this list will only be provided by the class
  377. \t\twhen it is being unpickled (removed from storage).  Normal
  378. \t\tuse is to call the class with no arguments and use the various
  379. \t\taddcounter functions (particularly, for end user's, the use of
  380. \t\taddcounterbybrowsing is the most common approach)  You might
  381. \t\twant to provide the list directly if you want to hard-code the
  382. \t\telements with which your query deals (and thereby avoid the
  383. \t\toverhead of unpickling the class).
  384. \t\t"""
  385.         self.volatilecounters = []
  386.         apply(BaseQuery.__init__, (self,) + args, namedargs)
  387.  
  388.     
  389.     def addperfcounter(self, object, counter, machine = None):
  390.         '''
  391. \t\tA "Performance Counter" is a stable, known, common counter,
  392. \t\tsuch as Memory, or Processor.  The use of addperfcounter by 
  393. \t\tend-users is deprecated, since the use of 
  394. \t\taddcounterbybrowsing is considerably more flexible and general.
  395. \t\tIt is provided here to allow the easy development of scripts
  396. \t\twhich need to access variables so common we know them by name
  397. \t\t(such as Memory|Available Bytes), and to provide symmetry with
  398. \t\tthe add inst counter method.
  399. \t\tusage:
  400. \t\t\tquery.addperfcounter(\'Memory\', \'Available Bytes\')
  401. \t\tIt is just as easy to access addcounter directly, the following
  402. \t\thas an identicle effect.
  403. \t\t\tquery.addcounter(\'Memory\', \'Available Bytes\')
  404. \t\t'''
  405.         BaseQuery.addcounter(self, object = object, counter = counter)
  406.  
  407.     
  408.     def addinstcounter(self, object, counter, machine = None, objtype = 'Process', volatile = 1, format = win32pdh.PDH_FMT_LONG):
  409.         """
  410. \t\tThe purpose of using an instcounter is to track particular
  411. \t\tinstances of a counter object (e.g. a single processor, a single
  412. \t\trunning copy of a process).  For instance, to track all python.exe
  413. \t\tinstances, you would need merely to ask:
  414. \t\t\tquery.addinstcounter('python','Virtual Bytes')
  415. \t\tYou can find the names of the objects and their available counters 
  416. \t\tby doing an addcounterbybrowsing() call on a query object (or by
  417. \t\tlooking in performance monitor's add dialog.)
  418. \t\t
  419. \t\tBeyond merely rearranging the call arguments to make more sense,
  420. \t\tif the volatile flag is true, the instcounters also recalculate
  421. \t\tthe paths of the available instances on every call to open the
  422. \t\tquery.
  423. \t\t"""
  424.         if volatile:
  425.             self.volatilecounters.append((object, counter, machine, objtype, format))
  426.         else:
  427.             self.paths[len(self.paths):] = self.getinstpaths(self, object, counter, machine, objtype, format)
  428.  
  429.     
  430.     def getinstpaths(self, object, counter, machine = None, objtype = 'Process', format = win32pdh.PDH_FMT_LONG):
  431.         '''
  432. \t\t### Not an end-user function
  433. \t\tCalculate the paths for an instance object. Should alter
  434. \t\tto allow processing for lists of object-counter pairs.
  435. \t\t'''
  436.         (items, instances) = win32pdh.EnumObjectItems(None, None, objtype, -1)
  437.         instances.sort()
  438.         
  439.         try:
  440.             cur = instances.index(object)
  441.         except ValueError:
  442.             return []
  443.  
  444.         temp = [
  445.             object]
  446.         
  447.         try:
  448.             while instances[cur + 1] == object:
  449.                 temp.append(object)
  450.                 cur = cur + 1
  451.         except IndexError:
  452.             pass
  453.  
  454.         paths = []
  455.         for ind in range(len(temp)):
  456.             paths.append(win32pdh.MakeCounterPath((machine, 'Process', object, None, ind, counter)))
  457.         
  458.         return paths
  459.  
  460.     
  461.     def open(self, *args, **namedargs):
  462.         '''
  463. \t\tExplicitly open a query:
  464. \t\tWhen you are needing to make multiple calls to the same query,
  465. \t\tit is most efficient to open the query, run all of the calls,
  466. \t\tthen close the query, instead of having the collectdata method
  467. \t\tautomatically open and close the query each time it runs.
  468. \t\tThere are currently no arguments to open.
  469. \t\t'''
  470.         apply(BaseQuery.open, (self,) + args, namedargs)
  471.         paths = []
  472.         for tup in self.volatilecounters:
  473.             paths[len(paths):] = apply(self.getinstpaths, tup)
  474.         
  475.         for path in paths:
  476.             
  477.             try:
  478.                 self.counters.append(win32pdh.AddCounter(self._base, path))
  479.                 self.curpaths.append(path)
  480.             except win32api.error:
  481.                 0
  482.                 0
  483.                 paths
  484.             except:
  485.                 0
  486.  
  487.         
  488.  
  489.     
  490.     def collectdatafor(self, totalperiod, period = 1):
  491.         '''
  492. \t\tNon-threaded collection of performance data:
  493. \t\tThis method allows you to specify the total period for which you would
  494. \t\tlike to run the Query, and the time interval between individual
  495. \t\truns.  The collected data is stored in query.curresults at the
  496. \t\t_end_ of the run.  The pathnames for the query are stored in
  497. \t\tquery.curpaths.
  498. \t\te.g.:
  499. \t\t\tquery.collectdatafor(30,2)
  500. \t\tWill collect data for 30seconds at 2 second intervals
  501. \t\t'''
  502.         tempresults = []
  503.         
  504.         try:
  505.             self.open()
  506.             for ind in xrange(totalperiod / period):
  507.                 tempresults.append(self.collectdata())
  508.                 time.sleep(period)
  509.             
  510.             self.curresults = tempresults
  511.         finally:
  512.             self.close()
  513.  
  514.  
  515.     
  516.     def collectdatawhile(self, period = 1):
  517.         '''
  518. \t\tThreaded collection of performance data:
  519. \t\tThis method sets up a simple semaphor system for signalling 
  520. \t\twhen you would like to start and stop a threaded data collection
  521. \t\tmethod.  The collection runs every period seconds until the
  522. \t\tsemaphor attribute is set to a non-true value (which normally
  523. \t\tshould be done by calling query.collectdatawhile_stop() .)
  524. \t\te.g.:
  525. \t\t\tquery.collectdatawhile(2)
  526. \t\t\t# starts the query running, returns control to the caller immediately
  527. \t\t\t# is collecting data every two seconds.
  528. \t\t\t# do whatever you want to do while the thread runs, then call:
  529. \t\t\tquery.collectdatawhile_stop()
  530. \t\t\t# when you want to deal with the data.  It is generally a good idea
  531. \t\t\t# to sleep for period seconds yourself, since the query will not copy
  532. \t\t\t# the required data until the next iteration:
  533. \t\t\ttime.sleep(2)
  534. \t\t\t# now you can access the data from the attributes of the query
  535. \t\t\tquery.curresults
  536. \t\t\tquery.curpaths
  537. \t\t'''
  538.         self.collectdatawhile_active = 1
  539.         thread.start_new_thread(self.collectdatawhile_slave, (period,))
  540.  
  541.     
  542.     def collectdatawhile_stop(self):
  543.         '''
  544. \t\tSignals the collectdatawhile slave thread to stop collecting data
  545. \t\ton the next logging iteration.
  546. \t\t'''
  547.         self.collectdatawhile_active = 0
  548.  
  549.     
  550.     def collectdatawhile_slave(self, period):
  551.         '''
  552. \t\t### Not a public function
  553. \t\tDoes the threaded work of collecting the data and storing it
  554. \t\tin an attribute of the class.
  555. \t\t'''
  556.         tempresults = []
  557.         
  558.         try:
  559.             self.open()
  560.             while self.collectdatawhile_active:
  561.                 tempresults.append(self.collectdata())
  562.                 time.sleep(period)
  563.             self.curresults = tempresults
  564.         finally:
  565.             self.close()
  566.  
  567.  
  568.     
  569.     def __getinitargs__(self):
  570.         return (self.paths,)
  571.  
  572.     
  573.     def __getstate__(self):
  574.         return self.volatilecounters
  575.  
  576.     
  577.     def __setstate__(self, volatilecounters):
  578.         self.volatilecounters = volatilecounters
  579.  
  580.  
  581.  
  582. class QueryError:
  583.     
  584.     def __init__(self, query):
  585.         self.query = query
  586.  
  587.     
  588.     def __repr__(self):
  589.         return '<Query Error in %s>' % repr(self.query)
  590.  
  591.     __str__ = __repr__
  592.  
  593.